#!/usr/bin/env perl

BEGIN { push @INC, "./lib"; }

use unixsys;
use HTTP::Date;
use Date::Calc qw(Time_to_Date Add_Delta_Days Date_to_Days Delta_Days);
use Getopt::Std;

my $os = new unixsys;

#
# Arg array
#
my %Args;

my %filehash;

my %sortedfilehash;

my %whohash;

my %untestedhash;
my %failedbuildhash;
my %passedtesthash;
my %failedtesthash;
my %failedunittesthash;
my %deletedhash;

my $uth = 0;
my $fbh = 0;
my $pth = 0;
my $fth = 0;
my $fuh = 0;

my $avgchanges;
my $avguntested;
my $avgfailedbuilds;
my $avgtested;
my $avgtestfail;
my $avgunitfail;

my $gstart;
my $gend;

my %statushash = (

    JOBS => {
        LABEL   => 'Total number of jobs run',
    },
    PASSEDBUILD => {
        LABEL   => 'Builds completed without errors',
        STATUS  => '0',
    },
    FAILEDTEST  => {
        LABEL   => 'Builds that failed smoke tests',
        STATUS  => '1',
    },
    FAILEDBUILD => {
        LABEL   => 'Builds that failed compilation',
        STATUS  => '2',
    },
    PASSEDTEST  => {
        LABEL   => 'Builds that passed smoke tests',
        STATUS  => '3',
    },
    FAILEDUNIT  => {
        LABEL   => 'Builds that failed unit testing',
        STATUS  => '8',
    },

);

my $globrecs;

#
# Get args
#
getopts('n:F:r:fdg', \%Args);

#
# Set globals from args
#
my $jobname   = $Args{n};
my $showfiles = $Args{f};
my $showdev   = $Args{d};
my $filter    = $Args{F};
my $generate  = $Args{g};
my $rootspec  = $Args{r};

if (!defined($jobname)) {
    usage(1);
}

if (defined($rootspec) && !$filter) {
    usage(1);
}

_processprimary();

_processfiles();

if ($showdev) {
    _devtotals();
}

if ($showfiles) {
    _displayfilelist();
}

print "\n\n";

sub _displayfilelist {

    printf("%-6s %-73s\n", "Commits", "Filename");
    printf("%-7s %-73s\n", "=======", "=============================");

    if ($generate) {
        open (F, ">$jobname.files");
    }
    foreach $key (reverse sort keys %sortedfilehash) {
        my ($r, $n) = split(/:/, $key);
        if ($rootspec) {
            if (defined($deletedhash{$n})) {
                my $len = length($n);
                my $picture = "%-7s %-".$len."s (deleted)\n";
                printf($picture, $r, $n);
            } else {
                my $len = length($n);
                my $picture = "%-7s %-".$len."s\n";
                printf($picture, $r, $n);
            }
        } else {
            my $len = length($n);
            my $picture = "%-7s %-".$len."s\n";
            printf($picture, $r, $n);
        }
        if ($generate) {
            print F "$n\n";
        }
    }
    if ($generate) {
        close (F);
    }

}

sub usage {

    my $exit = shift;

    print <<EOF;
jobstats.pl -n <jobname> 
           [-f] (show full filelist) 
           [-d] (developer stats)
           [-f filter1,filter2,filter3] (filter out branch names)
           [-g] (generate external file list)
           [-r source root] (determine deleted files, requires -f)
EOF

    exit $exit;

}

sub _devtotals {

    my $sqlquery;
    my @sqlarray;

    my @jobarray;

    my $recs;

    print "\nChanges by developer:\n\n";

    printf("%-11s %-8s %-8s %-14s %-10s %-10s %-10s\n", 
           "Name", 
           "Changes", 
           "Untested", 
           "Failed Builds",
           "Tested",
           "Test Fail",
           "Unit Fail"
           );
    printf("%-11s %-8s %-8s %-14s %-10s %-10s %-10s\n", 
           "========", 
           "========", 
           "========", 
           "=============", 
           "========", 
           "========", 
           "========");

    foreach $key (sort keys %whohash) {

        $recs++;

        my %temphash = ();
        
        my $fb  = 0;
        my $ut  = 0;
        my $pt  = 0;
        my $ft  = 0;
        my $fut = 0;

        my ($a, $b, $c, $d, $e);

        printf("%-11s %-8s ", $key, $whohash{$key}{RECORDS});

        @jobarray = split(/,/, $whohash{$key}{JOB});

        foreach $entry (@jobarray) {
            $temphash{$entry} = "";
        }

        foreach $j (keys %temphash) {
            if (defined($untestedhash{$j})) {
                $ut++;
            }
            if (defined($failedbuildhash{$j})) {
                $fb++;
            }
            if (defined($passedtesthash{$j})) {
                $pt++;
            }
            if (defined($failedtesthash{$j})) {
                $ft++;
            }
            if (defined($failedunittesthash{$j})) {
                $fut++;
            }
        }

        $tmptot = $ut+$pt+$ft;
        $pct    = sprintf("%d (%s%.2f)", $fb, "%", ($fb/$tmptot)*100);

        printf("%-8d %-14s %-10d %-10d %-10d\n", 
               $ut, 
               $pct,
               $pt, 
               $ft,
               $fut,
               );

        $a = sprintf("%s%.2f", "%", ($ut/$uth)*100);
        $b = sprintf("%s%.2f", "%", ($fb/$fbh)*100);
        if ($pth) {
            $c = sprintf("%s%.2f", "%", ($pt/$pth)*100);
        } else {
            $c = sprintf("%s%.2f", "%", 0);
        }
        $d = sprintf("%s%.2f", "%", ($ft/$fth)*100);
        if ($fuh) {
            $e = sprintf("%s%.2f", "%", ($fut/$fuh)*100);
        } else {
            $e = sprintf("%s%.2f", "%", 0);
        }

        printf("%20s %-8s %-14s %-10s %-10s %-10s\n", " ", 
               $a,
               $b,
               $c,
               $d,
               $e
               );

        $avgchanges += $whohash{$key}{RECORDS};
        $avguntested += $ut;
        $avgfailedbuilds += $fb;
        $avgtested += $pt;;
        $avgtestfail += $ft;
        $avgunitfail += $fut;

    }

    $avgchanges      = sprintf("%d", round($avgchanges/$recs));
    $avguntested     = sprintf("%d", round($avguntested/$recs));
    $avgfailedbuilds = sprintf("%d", round($avgfailedbuilds/$recs));
    $avgtested       = sprintf("%d", round($avgtested/$recs));
    $avgtestfail     = sprintf("%d", round($avgtestfail/$recs));
    $avgunitfail     = sprintf("%d", round($avgunitfail/$recs));

    $tmptot = $avguntested+$avgtested+$avgtestfail;
    $pct    = sprintf("%d (%s%.2f)", $avgfailedbuilds, "%", 
                     ($avgfailedbuilds/$tmptot)*100);

    print "\n========================================================\n";
    printf("\n%-11s %-8s %-8s %-14s %-10s %-10s %-10s\n", 
           "Average",
           $avgchanges,
           $avguntested,
           $pct,
           $avgtested,
           $avgtestfail,
           $avgunitfail
           );


}

sub _createweeklyaverage {

    my $sqlquery;
    my @sqlarray;

    my $start;
    my $end;

    $sqlquery = "select start from jobs where title=\"$jobname\" ".
                "order by job desc limit 1";

    @sqlarray = $os->run_sql_query($sqlquery);

    $end = $sqlarray[0];

    my ($eyear,$emonth,$eday, $ehour,$emin,$esec) = Time_to_Date($end);

    $gend = "$emonth/$eday/$eyear";

    $sqlquery = "select start from jobs where title=\"$jobname\" ".
                "order by job limit 1";

    @sqlarray = $os->run_sql_query($sqlquery);

    $start = $sqlarray[0];

    my ($syear,$smonth,$sday, $shour,$smin,$ssec) = Time_to_Date($start);

    $gstart = "$smonth/$sday/$syear";

    $days = Delta_Days($syear, $smonth, $sday, $eyear, $emonth, $eday);

    $workdays = sprintf("%d", ($days/7)*5);

    $workdays += $days%7;

    return sprintf("%.2f", $globrecs/$workdays);
    
}

sub _processfiles {

    my $sqlquery;
    my @sqlarray;

    my $total;
    my $unique=0;
    my $deleted=0;

    $sqlquery = "select job, changes from changes where title=\"$jobname\"";

    @sqlarray = $os->run_sql_query($sqlquery, ";");

    $total = @sqlarray;

    if ($showdev) {
        print STDERR "Processing $total records, please wait...\n";
    }

    foreach $entry (@sqlarray) {
        my ($job, $file, $ver, $change, $who) = split(/;/, $entry);
        my $r;
        $file =~ s/^\/\/depot\///g;
        if (defined($filter)) {
            my @filters = split(/,/, $filter);
            foreach $one (@filters) {
                $file =~ s/^$one\///g;
            }
        }
        if (defined($rootspec)) {
            if (! -f "$rootspec\/$file" && !defined($deletedhash{$file})) {
                $deletedhash{$file} = "";
                $deleted++;
            }
        }
        if (!defined($filehash{$file})) {
            %{ $filehash{$file} } = ( RECORDS => 1, );
        } else {
            $r = $filehash{$file}{RECORDS};
            $r++;
            delete($filehash{$file}{RECORDS});
            %{ $filehash{$file} } = ( RECORDS => $r, );
        }
        if (!defined($whohash{$who})) {
            %{ $whohash{$who} } = ( RECORDS => 1, JOB => $job);
        } else {
            $r  = $whohash{$who}{RECORDS};
            $oj = $whohash{$who}{JOB};
            $oj .= ",$job";
            $r++;
            delete($whohash{$who}{RECORDS});
            %{ $whohash{$who} } = ( RECORDS => $r, JOB => $oj);
        }
    }

    foreach $key (keys %filehash) {
        my $keynum = sprintf("%04d", $filehash{$key}{RECORDS});
        $sortedfilehash{"$keynum:$key"} = "";
        $unique++;
    }

    printf("%-34s : %-6s\n", "Total files changed", $total);
    printf("%-34s : %-6s\n", "Unique files changed", $unique);
    if ($rootspec) {
        printf("%-34s : %-6s\n", "Total files deleted", $deleted);
    }

}

sub _processprimary {

    my $key;

    my $sqlquery;
    my @sqlarray;

    $sqlquery = "select job from jobs where title=\"$jobname\"";

    @sqlarray = $os->run_sql_query($sqlquery);

    $globrecs = @sqlarray;

    if (!$globrecs) {
        print "No such job $jobname\n";
        exit 1;
    }

    my $average = _createweeklyaverage();

    print "\nReport for job $jobname from $gstart through $gend\n\n";
    print "====================================================\n\n";

    foreach $key (keys %statushash) {

        my $recs;
        my $status = $statushash{$key}{STATUS};

        $sqlquery = "select job from jobs where title=\"$jobname\"";

        @sqlarray = ();

        if (!defined($statushash{$key}{STATUS})) {
            printf("%-34s : %-6s\n", $statushash{$key}{LABEL}, $globrecs);
        } else {
            $sqlquery .= " and status=\"$status\"";
            @sqlarray = $os->run_sql_query($sqlquery);
            $recs     = @sqlarray;
            $hashname = $statushash{$key}{HASH};
            foreach $entry (@sqlarray) {
                if ($status == 0) {
                    $untestedhash{$entry} = "";
                    $uth++;
                } elsif ($status == 1) {
                    $failedtesthash{$entry} = "";
                    $fth++;
                } elsif ($status == 2) {
                    $failedbuildhash{$entry} = "";
                    $fbh++;
                } elsif ($status == 3) {
                    $passedtesthash{$entry} = "";
                    $pth++;
                } else {
                    $failedunittesthash{$entry} = "";
                    $fuh++;
                }
            }
            printf("%-34s : %-6s (%s%.2f)\n", $statushash{$key}{LABEL}, $recs,
                   "%", ($recs/$globrecs)*100);
        }

    }

    printf("%-34s : %-6s\n", "Average builds per day", $average);
    printf("%-34s : %-6s\n", "Average builds per week", $average*5);

}

sub round {
    my $number = shift;
    return int($number + .5);
}
